Add support for MSC4293 - Redact on Kick/Ban#18540
Conversation
tulir
left a comment
There was a problem hiding this comment.
Does synapse already pass through the field from /ban requests to the member event?
it does not, I have added support for that as well, missed it the first go around. |
anoadragon453
left a comment
There was a problem hiding this comment.
Not a complete review, as I still need to look at tests and the DB updates. But a solid start!
Also be aware that I typically advise people to aim for writing Complement tests when implementing unstable MSCs, such that other homeserver implementations can test against it when it comes time for them to implement the feature.
You don't need to do it here as you've already written a lot of unit tests, but for future reference.
|
Build errors are odd, I wonder if they are related to #18559 , as the errors mention base64: Otherwise I am not sure what I did to cause these |
|
Sorry, I broke develop :( This PR should fix it #18561 |
turt2live
left a comment
There was a problem hiding this comment.
drive-by SCT review to meet implementation requirements on the MSC. Overall, looks great - thank you!
The major detail would be removal of the event type filters, but that looks trivial enough to consider the MSC implemented regardless.
|
@anoadragon453 just checking that this is still on your radar |
There was a problem hiding this comment.
I'm wondering if this is the right architecture for dealing with such redactions. Pulling out all events sent by the user has a few potential issues: a) if there are a lot of events it might take a lot of time, and b) won't redact events that we haven't backfilled over federation yet. The MSC also seems to suggest that events should get unredacted if the ban is replaced with another state event without a redactions?
An alternate method may be to have a separate table that is room_redactions(room_id, sender), which we then check (as well as redactions table) when fetching the event? The new room_redactions would be updated when we add the ban/kick to the current_state_events table, and removed if it gets replaced?
There was a problem hiding this comment.
The MSC also seems to suggest that events should get unredacted if the ban is replaced with another state event without a redactions?
They shouldn't get unredacted, but the auto-redaction should cease for newly received events. I'll try to clarify this in the MSC itself.
An example series of events:
- Alice sends a message
- Bob bans Alice, with
redact_events: true - [Servers and clients redact Alice's message in step 1]
- Due to propagation delays, Alice's second message arrives after the ban. The server (and client, if it received it) redacts that message too.
- Later, Bob unbans Alice, setting
redact_events: false - Again due to propagation delays, or because Alice rejoined, Alice's third message arrives. It is not redacted.
The messages in steps 1 and 4 remain redacted even after step 5.
There was a problem hiding this comment.
@erikjohnston Looking at it I think a room_redactions table might work (with an added end_ts column or something to indicate the end of a redaction application in the case that the ban is rescinded, etc), but would still need to pull all of the user's event ids (but not full events) out of the db because they are needed to invalidate the cache.
I don't have a sense of the time difference to pull event ids out of the database vs pulling the full events so it is unclear to me whether having to still pull the ids will negate the benefit of the new table - right now the PR does both so it is an obvious improvement but is it enough or does another approach need to be found?
There was a problem hiding this comment.
with an added
end_tscolumn or something to indicate the end of a redaction application in the case that the ban is rescinded, etc
Wouldn't removing the row from the table be enough to stop redacting new events?
I don't have a sense of the time difference to pull event ids out of the database vs pulling the full events so it is unclear to me whether having to still pull the ids will negate the benefit of the new table
Pulling out only event IDs will certainly be much less data than full events, which should contribute directly to time taken executing the query. By how much depends on how large a user's events typically are. But you're right in that we'll still need to do the hard work of querying for every event a user has sent in a room.
The overview of this PR is:
The redactions table is updated to change the unique constraint from event_id to (event_id, redacts). This is so one event (a kick/ban membership) can redact multiple other events.
When a new event comes in over federation, add redacted_because to its unsigned and add a redaction to the local DB, then invalidate the event cache for that event.
/ban and /kick are updated with a org.matrix.msc4293.redact_events JSON body parameter. If provided, that field is added to the content of the ban/kick membership event.
When any event is persisted (local or over federation), all event IDs that a user has sent in a room are pulled out and entries in redactions are created for them. Each event has redacted_because added to it. The get_event cache is invalidated for each of these events.
What's more concerning to me is that the query to lookup all events a user has sent in a room happens is blocking during processing of a membership event. Perhaps that should be moved to a background task?
There was a problem hiding this comment.
but would still need to pull all of the user's event ids (but not full events) out of the db because they are needed to invalidate the cache.
I think you can invalidate those caches by room as well as by event ID?
Looking at it I think a
room_redactionstable might work (with an addedend_tscolumn or something to indicate the end of a redaction application in the case that the ban is rescinded, etc)
We would probably want to do this by some sort of stream ordering or whatever. We might do this as a two step:
- On receipt of ban, add room ID / target to table and record the range of stream orderings that should be redacted.
- On receipt of new events (e.g. via backfill), check if they match the ban and if so record them as redacted.
or something
anoadragon453
left a comment
There was a problem hiding this comment.
Agree with Erik's comment above.
Otherwise some minor notes on the current code - which is a lot more readable, thank you!
There was a problem hiding this comment.
with an added
end_tscolumn or something to indicate the end of a redaction application in the case that the ban is rescinded, etc
Wouldn't removing the row from the table be enough to stop redacting new events?
I don't have a sense of the time difference to pull event ids out of the database vs pulling the full events so it is unclear to me whether having to still pull the ids will negate the benefit of the new table
Pulling out only event IDs will certainly be much less data than full events, which should contribute directly to time taken executing the query. By how much depends on how large a user's events typically are. But you're right in that we'll still need to do the hard work of querying for every event a user has sent in a room.
The overview of this PR is:
The redactions table is updated to change the unique constraint from event_id to (event_id, redacts). This is so one event (a kick/ban membership) can redact multiple other events.
When a new event comes in over federation, add redacted_because to its unsigned and add a redaction to the local DB, then invalidate the event cache for that event.
/ban and /kick are updated with a org.matrix.msc4293.redact_events JSON body parameter. If provided, that field is added to the content of the ban/kick membership event.
When any event is persisted (local or over federation), all event IDs that a user has sent in a room are pulled out and entries in redactions are created for them. Each event has redacted_because added to it. The get_event cache is invalidated for each of these events.
What's more concerning to me is that the query to lookup all events a user has sent in a room happens is blocking during processing of a membership event. Perhaps that should be moved to a background task?
|
Right I have re-written the PR to take Erik's advice about creating a Re invalidating the cache, the cache I need to invalidate is the |
It looks like the synapse/synapse/util/caches/lrucache.py Lines 421 to 433 in 6dd48a5 And it looks like one can then call synapse/synapse/util/caches/lrucache.py Lines 784 to 804 in 6dd48a5 There's a helper function for it here: synapse/synapse/storage/databases/main/events_worker.py Lines 968 to 975 in 6dd48a5 |
|
@anoadragon453 thanks for pointing out the cache invalidation function utilizing the extra index. I had one question, which is that the function that populates the Otherwise I've changed the code to invalidate by room id rather than individual events, so I think this is ready for a re-review. |
|
@H-Shay Good question. Ideally whenever we get around to implementing an external cache, it will be invalidated by all relevant systems from the get go. I notice that there's currently no external equivalent to |
anoadragon453
left a comment
There was a problem hiding this comment.
Apologies again for slow review as we get through the PR backlog!
anoadragon453
left a comment
There was a problem hiding this comment.
A few more things, but overall this is nearly there.
anoadragon453
left a comment
There was a problem hiding this comment.
A few small things, and then I believe this is good to go!
|
complement failure looks to be a flake |
anoadragon453
left a comment
There was a problem hiding this comment.
This now LGTM. Thanks for your persistent efforts on this ✨
|
Thanks for the reviews @anoadragon453 😸 |
Adds support for MSC4293